//////////////////////////////////////////////////////////////////////////////////
//	Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <wx/dcbuffer.h>
#include <wx/pen.h> 
#include "linegraph.h"

#define SPECTER_PER_TONE		4.3125

#define NET_MAX_SPEED 			100

#define MAX_STORE_TIME			25*60*60

#define LEFT_SPACER				20
#define GRAPH_SPACER			20
#define TIME_LABEL_GAP			4
#define TRAFIC_LABEL_GAP		4
#define UP_SPACER				15


#define MIN_BLOCK_SIZE			10
#define MIN_TIME_BLOCK_SIZE		40

#define INIT_Y_VAL_MAX			20

static int nYBlocks[]= {	64,	32,	20, 16,	10, 8, 5, 4, 2,	1	};
static int nXBlocks[]= {	64,	32,	16,	8,	4,	2,	1	};

CLineGraph::CLineGraph(wxWindow* parent,size_t stMaxX, wxWindowID id ):
	wxPanel(parent, id,wxDefaultPosition, wxSize(100,200), wxTAB_TRAVERSAL),
	m_timer(this), m_nUpdateTime(1000),
	m_stMaxX(stMaxX), m_stMaxY(16), m_nTimePeriodSec(0), m_strMesureItemNameXTop(_("Tone") ),
	m_strMesureItemNameXBottom(_("kHz") ), m_dXBottomToTop(SPECTER_PER_TONE)

{
	SetBackgroundStyle(wxBG_STYLE_CUSTOM);
	
	Connect(wxEVT_PAINT, wxPaintEventHandler(CLineGraph::OnPaint));
	Connect(wxEVT_SIZE, wxSizeEventHandler(CLineGraph::OnSize));
	Connect(wxEVT_TIMER, wxTimerEventHandler(CLineGraph::OnTimer));
	
	if ( !m_timer.IsRunning() )
		m_timer.Start(m_nUpdateTime); //One per second

	SetMinSize( wxSize(stMaxX +LEFT_SPACER+GRAPH_SPACER, 200) );
}

CLineGraph::~CLineGraph()
{
	if ( m_timer.IsRunning() )
		m_timer.Stop();
}

void CLineGraph::SetTimePeriod(int nPer)
{
	m_nTimePeriodSec = nPer;
	Refresh();
}

void CLineGraph::SetData(const wxString& strName, const LINEVALS& vals)
{
	time_t tEvent = time(NULL);

	try
	{
		GRAPH* pGRaph = GetGraph(strName);

		//have call SetupGraphFirst
		if ( pGRaph )
		{
			DATAENTRY entry;
			entry.t		= tEvent;
			entry.vals	= vals;
			pGRaph->data.push_front( entry );
			CompressData( pGRaph->data );
		}
	}
	catch(...)
	{
	}
}

CLineGraph::GRAPH* CLineGraph::GetGraph(const wxString& strName)
{
	GRAPH* pGraph(NULL);

	GRAPHDATASTORAGE::iterator iCur = m_graphstorage.find(strName);

	if ( iCur!=m_graphstorage.end() )
	{
		pGraph = &iCur->second;
	}

	return pGraph;
}

void CLineGraph::SetUpGraph(const wxString& strName, size_t stYMax, const GRAPHVISUAL& visual)
{
	GRAPH graph;
	graph.stMaxY = stYMax;
	graph.visual = visual;
	m_graphstorage[strName] = graph;
}

void CLineGraph::CompressData(GRAPHDATA& dataOld)
{
	time_t tNow = time(NULL);

	if ( dataOld.size()>10 )
	{
		GRAPHDATA data;

		GRAPHDATA::iterator iCur = dataOld.begin();

		//keep latest record untouched
		data.push_back( *iCur );

		++iCur;

		for ( ;iCur!= dataOld.end();++iCur )
		{
			DATAENTRY& a = *iCur;

			if ( ++iCur==dataOld.end() ) break;

			DATAENTRY& b = *iCur;

			if ( tNow - b.t > MAX_STORE_TIME )
				break;

			wxDateTime aTime(a.t);
			wxDateTime bTime(b.t);

			DATAENTRY vNew;

			if ( aTime.GetHour() == bTime.GetHour() &&
				aTime.GetDayOfYear() == bTime.GetDayOfYear() )
			{
				unsigned int x1,x2;

				for(size_t i=0;i<m_stMaxX;i++)
				{
					x1=0;
					x2=0;

					if ( a.vals.size()>i )
					{
						x1 = a.vals[i];
					}
					
					if ( b.vals.size()>i )
					{
						x2 = b.vals[i];
					}

					vNew.vals.push_back( (x1+x2)/2 );
				}

				vNew.t = a.t;
				data.push_back( vNew );
			}
		}

		dataOld = data;
	}
}

void CLineGraph::SetUpdateInterVal(unsigned int nUpdateTime)
{
	if ( m_timer.IsRunning() )
		m_timer.Stop();
	
	m_nUpdateTime = nUpdateTime;
	
	m_timer.Start(m_nUpdateTime);
}

void CLineGraph::OnTimer(wxTimerEvent& event)
{
	Refresh();	
}

void CLineGraph::SetZonesHorizontal(const ZONELIST& lstZone)
{
	m_lstZoneHorizontal = lstZone;

	Refresh();
}


void CLineGraph::OnSize(wxSizeEvent& event)
{
	Refresh();
}

void CLineGraph::OnPaint(wxPaintEvent& event)
{
	wxSize szMe = GetClientSize();
	wxBufferedPaintDC dc(this);

	wxBrush br(GetBackgroundColour());

	//Clear
	dc.SetBackground(br);
	dc.Clear();

	wxRect rectGraphArea;
	DrawGrid( dc, rectGraphArea );

	//Draw bar first
	for(GRAPHDATASTORAGE::iterator iCur=m_graphstorage.begin();
		iCur!=m_graphstorage.end();++iCur)
	{
		const GRAPH& graph = iCur->second;

		if ( graph.visual.cType == cGraphTypeBar )
		{
			DrawGraph(dc, graph, rectGraphArea);
		}
	}

	//Draw line
	for(GRAPHDATASTORAGE::iterator iCur=m_graphstorage.begin();
		iCur!=m_graphstorage.end();++iCur)
	{
		const GRAPH& graph = iCur->second;

		if ( graph.visual.cType == cGraphTypeLine )
		{
			DrawLineGraph(dc, graph, rectGraphArea);
		}
	}

	rectGraphArea.Deflate(1,1);
	DrawGridLines(dc, rectGraphArea.x, rectGraphArea.y, rectGraphArea.width, rectGraphArea.height);
}

const LINEVALS& CLineGraph::GetData(const GRAPH& graph)
{
	time_t t = time(NULL);

	static LINEVALS gDummyData;

	if ( !graph.data.empty() )
	{
		if ( m_nUpdateTime )
		{
			GRAPHDATA::const_iterator iCur = graph.data.begin();

			for( ;iCur!=graph.data.end();++iCur )
			{
				const DATAENTRY& entry = *iCur;

				wxDateTime aTime(entry.t);
				wxDateTime bTime(t - m_nTimePeriodSec);
				
				if ( aTime.GetHour() == bTime.GetHour() &&
					aTime.GetDayOfYear() == bTime.GetDayOfYear() )
				{
					return const_cast<const LINEVALS&>(iCur->vals);
				}
			}
		}
		else
		{
			return graph.data.front().vals;
		}
	}

	return gDummyData;
}

void CLineGraph::CalculateBlockParams( int nLineLength, int* nBlocksMap, int nMapSize,
									   int nBlockMinSize, int &nBlockSize, int& nBlockCount, size_t stMax )
{
	nBlockCount = 1;
	nBlockSize  = nLineLength;

	for (int i=0;i<nMapSize;i++)
	{
		size_t tBlocks = nBlocksMap[i];

		if ( tBlocks>stMax )
		{
			tBlocks = stMax;
		}

		if ( nLineLength/tBlocks>=nBlockMinSize )
		{
			nBlockCount = tBlocks;
			nBlockSize  = nLineLength/nBlockCount;
			break;
		}
	}
}

void CLineGraph::DrawGrid( class wxBufferedPaintDC& dc, 
		wxRect&  rectGraphArea)
{
	wxSize szMe = GetClientSize();
	int nLeftSpacer = LEFT_SPACER;

	int xStart = nLeftSpacer;
	int yStart;
	int w = szMe.GetWidth()-nLeftSpacer-GRAPH_SPACER;
	int h = szMe.GetHeight();

	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);
	dc.SetFont(font);

	int wText, hText;
	dc.GetTextExtent(wxT("R"), &wText, &hText);

	h-=2*hText+4;

	DrawLegend(dc, w, h);

	CalculateBlockParams(h, nYBlocks,sizeof(nYBlocks)/sizeof(nYBlocks[0]),
		MIN_BLOCK_SIZE, m_nTrafBlockSize, m_nTrafBlockCount, m_stMaxY);

	CalculateBlockParams(w, nXBlocks,sizeof(nXBlocks)/sizeof(nXBlocks[0]),
		MIN_TIME_BLOCK_SIZE, m_nXBlockSize, m_nXBlockCount, m_stMaxX);

	//Correct Height
	h=m_nTrafBlockCount*m_nTrafBlockSize;

	/*yStart = (szMe.GetHeight()-h)/2;*/
	yStart = UP_SPACER;

	//Correct Width
	w=m_nXBlockCount*m_nXBlockSize;

	rectGraphArea.x = xStart;
	rectGraphArea.y = yStart;
	rectGraphArea.width  = w;
	rectGraphArea.height = h;

	//Draw BOX
	wxBrush br(*wxWHITE);
	dc.SetBrush(br);

	wxPen   pn(*wxBLACK);
	dc.SetPen(pn);

	dc.DrawRectangle(rectGraphArea);

	DrawXLabels(dc,rectGraphArea.x, 0 , rectGraphArea.width, 0, true );
	DrawXLabels(dc,rectGraphArea.x, rectGraphArea.y , rectGraphArea.width, rectGraphArea.height, false);


	//Draw bar first
	for(GRAPHDATASTORAGE::iterator iCur=m_graphstorage.begin();
		iCur!=m_graphstorage.end();++iCur)
	{
		const GRAPH& graph = iCur->second;

		if ( graph.visual.cPos == cGraphLabelPositionLeft )
		{
			DrawYLabels(dc, rectGraphArea.x, rectGraphArea.y,
				rectGraphArea.width, rectGraphArea.height, graph.stMaxY);
			break;
		}
	}

	//Draw line
	for(GRAPHDATASTORAGE::iterator iCur=m_graphstorage.begin();
		iCur!=m_graphstorage.end();++iCur)
	{
		const GRAPH& graph = iCur->second;

		if ( graph.visual.cPos == cGraphLabelPositionRight )
		{
			DrawYLabelsRight(dc, rectGraphArea.x, rectGraphArea.y,
				rectGraphArea.width, rectGraphArea.height, graph.stMaxY);
			break;
		}
	}

	wxRect rc(rectGraphArea);
	rc.Deflate(1,1);

	DrawZones(dc, rc.x, rc.y , rc.width, rc.height, rectGraphArea);
}

void CLineGraph::DrawZones(class wxBufferedPaintDC& dc, int x, int y, int w, int h,
						   const wxRect&  rectGraphArea)
{
	unsigned int lUpLevel = CalculateUpLevel();
	double lPerUnit  = double(h)/lUpLevel;

	lPerUnit=lPerUnit?lPerUnit:1;

	ZONELIST::const_iterator iCur;

	wxRect rect(rectGraphArea);
	dc.SetClippingRegion(rect.Deflate(1,1) );

	for( iCur=m_lstZoneHorizontal.begin();iCur!=m_lstZoneHorizontal.end();++iCur )
	{
		const ZONERANGE& entry = *iCur;

		//Draw BOX
		wxBrush br(entry.color);
		wxPen   pn(entry.color);
		dc.SetBrush(br);
		dc.SetPen(pn);

		int yFrom = y +h - lPerUnit*entry.nFrom;
		int yTo   = y +h - lPerUnit*entry.nTo;

		if ( yFrom>0 )
		{
			if ( yTo<0 )
				yTo=y;

			dc.DrawRectangle(x, yTo, w, yFrom-yTo);
		}
	}

	dc.DestroyClippingRegion();
}

//Horizontal labels
void CLineGraph::DrawXLabels(class wxBufferedPaintDC& dc, int x, int y, int w, int h, bool bBottom)
{
	int wText, hText;
	int yLab = bBottom?0:y+h+TIME_LABEL_GAP;
	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);

	dc.SetFont(font);

	for (int i=0;i<=m_nXBlockCount;i++)
	{
		int xTxtCenter = x + i*m_nXBlockSize;

		int nPerBlock = m_stMaxX/m_nXBlockCount;

		wxString strLabel = FormatXLabel( nPerBlock*i, bBottom);

		dc.GetTextExtent(strLabel, &wText, &hText);

		int xTxt = xTxtCenter-wText/2;


		/*
		if (i==m_nXBlockCount)
		{
		xTxt = xTxtCenter;
		}*/

		dc.DrawText( strLabel, xTxt, yLab);
		//dc.DrawRotatedText (strLabel,  xTxt, yLab, 120 );
	}
}

//Vertical labels
void CLineGraph::DrawYLabels( class wxBufferedPaintDC& dc, int x, int y, int w, int h, int nMaxY)
{
	unsigned int lUpLevel  = nMaxY;
	unsigned int lPerBlock = lUpLevel/m_nTrafBlockCount;

	int wText, hText;
	
	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);
	dc.SetFont(font);

	for (int i=0;i<=m_nTrafBlockCount;i++)
	{
		int yTxtCenter = y +h - i*m_nTrafBlockSize;

		wxString strLabel = FormatLabel(i*lPerBlock);

		dc.GetTextExtent(strLabel, &wText, &hText);

		int yTxt = yTxtCenter-hText/2;
		int xTxt = x-wText-TRAFIC_LABEL_GAP;

		dc.DrawText( strLabel, xTxt, yTxt );
	}
}

//Vertical labels
void CLineGraph::DrawYLabelsRight( class wxBufferedPaintDC& dc, int x, int y, int w, int h, int nMaxY)
{
	unsigned int lUpLevel  = nMaxY;
	unsigned int lPerBlock = lUpLevel/m_nTrafBlockCount;

	int wText, hText;
	
	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);
	dc.SetFont(font);

	for (int i=0;i<m_nTrafBlockCount;i++)
	{
		int yTxtCenter = y +h - i*m_nTrafBlockSize;

		wxString strLabel = FormatLabel(i*lPerBlock);

		dc.GetTextExtent(strLabel, &wText, &hText);

		int yTxt = yTxtCenter-hText/2;
		int xTxt = x+w;

		dc.DrawText( strLabel, xTxt, yTxt );
	}
}


wxString CLineGraph::FormatXLabel(int nTimeBlockIndex, bool bBottom)
{
	wxString strLabel;

	if ( bBottom )
	{
		strLabel = wxString::Format(wxT("%u"), nTimeBlockIndex);

		if ( nTimeBlockIndex==m_stMaxX)
		{
			strLabel+=wxT(" ");
			strLabel+=m_strMesureItemNameXTop;
		}
	}
	else
	{
		strLabel = wxString::Format(wxT("%u"), (unsigned int)(m_dXBottomToTop*nTimeBlockIndex));

		if ( nTimeBlockIndex==m_stMaxX)
		{
			strLabel+=wxT(" ");
			strLabel+=m_strMesureItemNameXBottom;
		}
	}

	return strLabel;
}


void CLineGraph::DrawGridLines(class wxBufferedPaintDC& dc, int x, int y, int w, int h)
{
	wxPen pen(*wxBLACK,1,wxDOT);
	dc.SetPen(pen);

	//Horizontal blocks
	for (int i=1;i<m_nTrafBlockCount;i++)
	{
		int yBl = y+h - i*m_nTrafBlockSize;

		dc.DrawLine(x,yBl, x+w,yBl);
	}

	//Vert Blocks
	for (int i=1;i<m_nXBlockCount;i++)
	{
		int xBl = x+w - i*m_nXBlockSize;

		dc.DrawLine(xBl,y, xBl,y+h);
	}
}

//----------------------------------------------------------------
void CLineGraph::DrawLegend(  wxBufferedPaintDC& dc, int&  wAll, int&  hAll)
{
	wxSize szMe = GetClientSize();

	int w(0);
	int h(0);
	int wBox(0);

	DrawLegendBottom(  dc, 0, w, h, false );

	//if ( w<szMe.x )
	{
		int xStart = (szMe.x - w)/2;
		int nLeftSpacer = LEFT_SPACER;

		if (xStart<0 ) xStart = 0;

		DrawLegendBottom(  dc, xStart, w, h, true );

		hAll-=h+10;
	}
}

void CLineGraph::DrawLegendBottom(  wxBufferedPaintDC& dc, int x,
							 int& wTotal, int& hTotal, bool bDraw )
{
	int wTextLabel, hTextLabel;

	wxSize szClient = GetClientSize();
	int hMe = szClient.y;

	const int nBorder = 1;
	const int nLineW = 10;
	const int nLineH = 1;
	const int nBoxPenW = 1;
	int xStart = x;

	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);
	dc.SetFont(font);

	for( GRAPHDATASTORAGE::const_iterator iCur = m_graphstorage.begin();
			iCur != m_graphstorage.end();++iCur )
	{
		const GRAPH& data = iCur->second;

		dc.GetTextExtent(iCur->first, &wTextLabel, &hTextLabel);

		hTotal = nBorder+nBoxPenW+nBorder+nBorder+nBoxPenW+nBorder;

		//1. Draw Box
		xStart+=nBorder+10;

		wxBrush br(/*GetBackgroundColour()*/*wxWHITE);

		dc.SetPen(*wxBLACK);
		dc.SetBrush(br);

		int xBox = xStart;
		int yBox = hMe-hTextLabel;
		int wBox = nBoxPenW+nBorder+nLineW+nBorder+nBorder+nLineW+nBorder+nBoxPenW;
		int hBox = hTextLabel-2;
		int nYText = yBox+(hBox-hTextLabel)/2;

		if ( bDraw &&
			 xStart-x+wBox+nBorder+wTextLabel+5>szClient.x )
		{
			break;
		}

		if ( bDraw )
		{
			dc.DrawRectangle(xBox, yBox, wBox, hBox );
		}

		size_t i=0;

		const ZONELIST& lstColors = data.visual.lstColors;

		//2. Draw Line
		if ( bDraw )
		{
			for(ZONELIST::const_iterator iColour = lstColors.begin();
				iColour!= lstColors.end();++iColour)
			{
				const ZONERANGE& range = *iColour;

				wxPen     pnLine (range.color);
				wxBrush   pnBrush(range.color);

				dc.SetPen(pnLine);
				dc.SetBrush(pnBrush);

				int nHPerLine = (hBox-2)/(lstColors.empty()?1:lstColors.size());
				dc.DrawRectangle(1+xBox, 1+yBox+i*nHPerLine, wBox-2, nHPerLine );

				i++;
			}
		}

		xStart+=wBox+nBorder;

		//5. Draw Text Label
		if ( bDraw )
		{
			dc.DrawText(iCur->first, xStart, nYText); 
		}

		xStart+=nBorder+wTextLabel+5;
	}

	wTotal = xStart;
}
//----------------------------------------------------------------

//new>old

#define Y_DELTA 0

void CLineGraph::DrawGraph(class wxBufferedPaintDC& dc,  const GRAPH& graph,
							 const wxRect& rectOrigin)
{
	wxRect rect(rectOrigin.Deflate(0,2));

	rect.height = rect.height;  
	
	const LINEVALS& data =	GetData( graph );

	size_t stSkip=0;

	for ( LINEVALS::const_reverse_iterator iR = data.rbegin();iR!=data.rend();++iR )
	{
		if (*iR) break;
		stSkip++;
	}

	dc.DestroyClippingRegion();
	dc.SetClippingRegion( rect );

	wxColor color(*wxGREEN), colorOld(*wxBLACK);
	wxPen	pen(*wxBLACK);
	wxBrush brush(*wxBLACK);
	
	const ZONELIST& lstColors = graph.visual.lstColors;

	wxPointList list;

	dc.SetPen( pen );

	for(size_t i=0;i<data.size()-stSkip;++i)
	{
		unsigned int nVal = data[i];

		int x = rect.x+1;
		int nValGraph = (nVal*rect.GetHeight())/graph.stMaxY;

		double xSale = ((double)rect.GetWidth())/m_stMaxX;
		x+=xSale*i;

		for(ZONELIST::const_iterator iCur = lstColors.begin();
			iCur!= lstColors.end();++iCur)
		{
			const ZONERANGE& range = *iCur;

			if ( i>=range.nFrom && i<range.nTo )
			{
				color = range.color;
				break;
			}
		}

		if ( color!=colorOld )
		{
			colorOld = color;
			
			if ( list.size() >4 )
			{
				wxPoint* pFirst = (wxPoint*)list[0];
				wxPoint* pLast  = (wxPoint*)list[ list.size()-1];

				//Add last points
				list.Append( new wxPoint(pLast->x, rect.y+rect.GetHeight()+Y_DELTA) );
				list.Append( new wxPoint(pFirst->x, pFirst->y) );

				dc.DrawPolygon( &list  );

				wxPointList::iterator iCur=list.begin();
				for (iCur=list.begin();iCur!=list.end();iCur++)
				{
					delete (wxPoint*)*iCur;
					*iCur = NULL;
				}

				list.erase( list.begin(), list.end() );
			}

			brush.SetColour(color);
			dc.SetBrush( brush );

			wxColor colorPen( 0.8*color.Red(), 0.8*color.Green(), 0.8*color.Blue() );
			pen.SetColour( colorPen );
			dc.SetPen(pen);
		}

		if ( list.empty() )
		{
			 //2 to avoid buggy drawing
			list.Append( new wxPoint(x, rect.y+rect.GetHeight()+Y_DELTA) );
		}

		list.Append( new wxPoint(x, rect.GetBottom()-nValGraph) );
	}

	if ( !list.empty() )
	{
		//Add last points
		wxPoint* pLast = (wxPoint*)list[ list.size()-1];
		list.Append( new wxPoint( pLast->x, rect.y+rect.GetHeight()+Y_DELTA));

		wxPoint* p = (wxPoint*)list[0];
		list.Append( new wxPoint(p->x, p->y) );

		if ( list.size()>4 )
		{
			dc.DrawPolygon( &list  );
		}

		wxPointList::iterator iCur=list.begin();
		for (iCur=list.begin();iCur!=list.end();iCur++)
		{
			delete (wxPoint*)*iCur;
			*iCur = NULL;
		}
	}

	dc.DestroyClippingRegion();
}

void CLineGraph::DrawLineGraph( class wxBufferedPaintDC& dc,
							    const GRAPH& graph, const wxRect& rect )
{
	const LINEVALS& data =	GetData( graph );

	dc.DestroyClippingRegion();
	dc.SetClippingRegion( rect );

	wxColor color(*wxRED), colorOld(*wxBLACK);
	wxPen	pen(color, graph.visual.nPenWidth);

	const ZONELIST& lstColors = graph.visual.lstColors;

	wxPointList list;

	for(size_t i=0;i<data.size();++i)
	{
		for(ZONELIST::const_iterator iCur = lstColors.begin();
			iCur!= lstColors.end();++iCur)
		{
			const ZONERANGE& range = *iCur;

			if ( i>=range.nFrom && i<range.nTo )
			{
				color = range.color;
				break;
			}
		}

		if ( color!=colorOld )
		{
			colorOld = color;
			pen.SetColour(color);
			dc.SetPen( pen );

			if ( !list.empty() &&
				list.size() >2 )
			{
				dc.DrawSpline( &list  );

				wxPointList::iterator iCur=list.begin();
				for (iCur=list.begin();iCur!=list.end();iCur++)
				{
					delete (wxPoint*)*iCur;
					*iCur = NULL;
				}
			}
		}

		unsigned int nVal = data[i];

		int x = rect.x;
		int nValGraph = (nVal*rect.GetHeight())/graph.stMaxY;

		double xSale = ((double)rect.GetWidth())/m_stMaxX;
		x+=xSale*i; 

		list.Append(new wxPoint(x, rect.GetBottom()-nValGraph) );
	}

	if ( list.size()>2 )
	{
		dc.DrawSpline( &list  );
	}

	wxPointList::iterator iCur=list.begin();

	for (iCur=list.begin();iCur!=list.end();iCur++)
	{
		delete (wxPoint*)*iCur;
		*iCur = NULL;
	}

	dc.DestroyClippingRegion();
}

////////////////////////////////////////////////////////////////////////////////////////////
//UTL
unsigned int CLineGraph::CalculateUpLevel()
{
	return m_stMaxY;
}

wxString CLineGraph::FormatLabel( unsigned long lVal)
{
	if ( lVal )
	{
		const wxString strFormat = _("%3.u %s");
		return  wxString::Format(strFormat, lVal, m_strMesureItemName.c_str());
	}

	return wxT("");
}

////////////////////////////////////////////////////////////////////////////////////////////
// Data Management
void  CLineGraph::Reset()
{
	/*
	time_t tNow = time(NULL);

	DATAENTRY entry;
	entry.t = tNow;

	for(GRAPHDATASTORAGE::iterator iCur=m_graphstorage.begin();
		iCur!=m_graphstorage.end();++iCur)
	{
		GRAPH& graph = iCur->second;
		graph.data.push_front(entry);
	}*/
}

